/*
 * callback_vs_coroutine_state_machine.cpp
 *
 * 展示三种实现同一异步流程的方式，方便对比优缺点：
 *   1. “回调地狱”写法：多层嵌套 async_wait。
 *   2. 显式状态机：单一 async_wait 回调 + 状态枚举，逻辑集中。
 *   3. C++20 协程：近似同步的线性写法，编译器自动生成状态机。
 *
 * 模拟的业务步骤（每一步都用定时器模拟异步等待）：
 *   - 建立连接 -> 发送认证请求 -> 等待认证响应 -> 发送查询 -> 等待查询结果
 *
 * 为避免输出互相交错，三种写法使用独立 io_context，按顺序执行。
 *
 * 构建 & 运行：
 *   g++ -std=c++20 -O2 callback_vs_coroutine_state_machine.cpp -o demo \
 *       -lboost_system -lpthread
 *   ./demo
 */

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <chrono>
#include <iostream>
#include <memory>

namespace asio = boost::asio;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;
using boost::system::error_code;
using namespace std::chrono_literals;

// -----------------------------------------------------------------------------
// 1. “回调地狱”示例：每个步骤在前一步的回调里继续嵌套。
// -----------------------------------------------------------------------------
void start_callback_hell(asio::io_context& io) {
    std::cout << "\n=== callback hell ===\n";
    std::cout << "[callback] Connecting...\n";

    // 第一步：等待连接完成。
    auto connect_timer = std::make_shared<asio::steady_timer>(io);
    connect_timer->expires_after(200ms);
    connect_timer->async_wait([&io, connect_timer](const error_code& ec) {
        if (ec) {
            std::cerr << "[callback] connect timer error: " << ec.message() << "\n";
            return;
        }
        std::cout << "[callback] Connected. Sending auth...\n";

        // 第二步：模拟发送认证请求。
        auto auth_timer = std::make_shared<asio::steady_timer>(io);
        auth_timer->expires_after(300ms);
        auth_timer->async_wait([&io, auth_timer](const error_code& ec) {
            if (ec) {
                std::cerr << "[callback] auth write error: " << ec.message() << "\n";
                return;
            }
            std::cout << "[callback] Auth request sent. Waiting for auth response...\n";

            // 第三步：等待认证响应。
            auto auth_resp_timer = std::make_shared<asio::steady_timer>(io);
            auth_resp_timer->expires_after(250ms);
            auth_resp_timer->async_wait([&io, auth_resp_timer](const error_code& ec) {
                if (ec) {
                    std::cerr << "[callback] auth read error: " << ec.message() << "\n";
                    return;
                }
                std::cout << "[callback] Auth OK. Sending query...\n";

                // 第四步：发送查询请求。
                auto query_timer = std::make_shared<asio::steady_timer>(io);
                query_timer->expires_after(200ms);
                query_timer->async_wait([&io, query_timer](const error_code& ec) {
                    if (ec) {
                        std::cerr << "[callback] query write error: " << ec.message() << "\n";
                        return;
                    }
                    std::cout << "[callback] Query sent. Waiting for data...\n";

                    // 第五步：等待查询结果。
                    auto data_timer = std::make_shared<asio::steady_timer>(io);
                    data_timer->expires_after(250ms);
                    data_timer->async_wait([data_timer](const error_code& ec) {
                        if (ec) {
                            std::cerr << "[callback] data read error: " << ec.message() << "\n";
                            return;
                        }
                        std::cout << "[callback] Received payload: {\"items\": 42}\n";
                        std::cout << "[callback] Session finished.\n";
                    });
                });
            });
        });
    });
}

// -----------------------------------------------------------------------------
// 2. 显式状态机：使用单一 async_wait 回调，根据状态切换推进流程。
// -----------------------------------------------------------------------------
void start_state_machine(asio::io_context& io) {
    std::cout << "\n=== state machine ===\n";

    struct Session : std::enable_shared_from_this<Session> {
        // 枚举所有可能的步骤，明确状态转移。
        enum class Stage {
            Connecting,
            ConnectedSendingAuth,
            AuthSentWaitingResponse,
            AuthOkSendingQuery,
            QuerySentWaitingData,
            Done
        };

        asio::steady_timer timer;  // 单一定时器，反复重用。
        Stage stage = Stage::Connecting;  // 当前状态。

        explicit Session(asio::io_context& io_ctx)
            : timer(io_ctx) {}

        // 启动状态机：进入第一步。
        void start() {
            std::cout << "[state] Connecting...\n";
            schedule_next(200ms, Stage::ConnectedSendingAuth);
        }

        // 统一的调度函数：设置等待时间和下一个状态。
        void schedule_next(std::chrono::milliseconds delay, Stage next_stage) {
            stage = next_stage;
            timer.expires_after(delay);

            auto self = shared_from_this();
            timer.async_wait([self](const error_code& ec) {
                if (ec) {
                    std::cerr << "[state] timer error: " << ec.message() << "\n";
                    return;
                }
                self->advance();  // 定时器超时时推进状态。
            });
        }

        // 根据当前状态执行对应的动作，并调度下一步。
        void advance() {
            switch (stage) {
                case Stage::ConnectedSendingAuth:
                    std::cout << "[state] Connected. Sending auth...\n";
                    schedule_next(300ms, Stage::AuthSentWaitingResponse);
                    break;
                case Stage::AuthSentWaitingResponse:
                    std::cout << "[state] Auth request sent. Waiting for auth response...\n";
                    schedule_next(250ms, Stage::AuthOkSendingQuery);
                    break;
                case Stage::AuthOkSendingQuery:
                    std::cout << "[state] Auth OK. Sending query...\n";
                    schedule_next(200ms, Stage::QuerySentWaitingData);
                    break;
                case Stage::QuerySentWaitingData:
                    std::cout << "[state] Query sent. Waiting for data...\n";
                    schedule_next(250ms, Stage::Done);
                    break;
                case Stage::Done:
                    std::cout << "[state] Received payload: {\"items\": 42}\n";
                    std::cout << "[state] Session finished.\n";
                    break;
                case Stage::Connecting:
                default:
                    // 正常流程不会回到 Connecting。
                    break;
            }
        }
    };

    // 创建会话对象并启动状态机。
    auto session = std::make_shared<Session>(io);
    session->start();
}

// -----------------------------------------------------------------------------
// 3. 协程辅助函数：等待指定时间，并打印日志。
// -----------------------------------------------------------------------------
awaitable<void> async_delay(std::chrono::milliseconds delay, std::string_view step) {
    // 获取当前协程所在的 executor（用于构造 timer）。
    auto executor = co_await asio::this_coro::executor;

    asio::steady_timer timer(executor);
    timer.expires_after(delay);
    co_await timer.async_wait(use_awaitable);  // 挂起协程直到定时器超时。

    std::cout << "[coroutine] " << step << "\n";
}

// -----------------------------------------------------------------------------
// 3. 协程版本：逻辑线性展开，每一步只需 co_await 对应延迟。
// -----------------------------------------------------------------------------
awaitable<void> run_coroutine_session() {
    std::cout << "\n=== coroutine flow ===\n";

    std::cout << "[coroutine] Connecting...\n";
    co_await async_delay(200ms, "Connected.");

    std::cout << "[coroutine] Sending auth...\n";
    co_await async_delay(300ms, "Auth request sent.");

    std::cout << "[coroutine] Waiting for auth response...\n";
    co_await async_delay(250ms, "Auth OK.");

    std::cout << "[coroutine] Sending query...\n";
    co_await async_delay(200ms, "Query sent.");

    std::cout << "[coroutine] Waiting for data...\n";
    co_await async_delay(250ms, "Received payload: {\"items\": 42}");

    std::cout << "[coroutine] Session finished.\n";
    co_return;
}

// -----------------------------------------------------------------------------
// 主函数：顺序执行三种实现，让输出清晰分段。
// -----------------------------------------------------------------------------
int main() {
    try {
        {
            asio::io_context io_cb;
            start_callback_hell(io_cb);  // 回调地狱
            io_cb.run();
        }
        {
            asio::io_context io_sm;
            start_state_machine(io_sm);  // 显式状态机
            io_sm.run();
        }
        {
            asio::io_context io_co;
            co_spawn(io_co, run_coroutine_session(), detached);  // C++20 协程
            io_co.run();
        }
    } catch (const std::exception& ex) {
        std::cerr << "Fatal error: " << ex.what() << '\n';
        return 1;
    }
    return 0;
}